* the offset.
*/
cairo_pattern_t *
-_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
+_st_create_shadow_cairo_pattern (StShadow *shadow_spec_in,
cairo_pattern_t *src_pattern)
{
+ g_autoptr(StShadow) shadow_spec = NULL;
static cairo_user_data_key_t shadow_pattern_user_data;
cairo_t *cr;
cairo_surface_t *src_surface;
gint width_in, height_in, rowstride_in;
gint width_out, height_out, rowstride_out;
cairo_matrix_t shadow_matrix;
+ double xscale_in, yscale_in;
int i, j;
- g_return_val_if_fail (shadow_spec != NULL, NULL);
+ g_return_val_if_fail (shadow_spec_in != NULL, NULL);
g_return_val_if_fail (src_pattern != NULL, NULL);
if (cairo_pattern_get_surface (src_pattern, &src_surface) != CAIRO_STATUS_SUCCESS)
width_in = cairo_image_surface_get_width (src_surface);
height_in = cairo_image_surface_get_height (src_surface);
+ cairo_surface_get_device_scale (src_surface, &xscale_in, &yscale_in);
+
+ if (xscale_in != 1.0 || yscale_in != 1.0)
+ {
+ /* Scale the shadow specifications in a temporary copy so that
+ * we can work everywhere in absolute surface coordinates */
+ double scale = (xscale_in + yscale_in) / 2.0;
+ shadow_spec = st_shadow_new (&shadow_spec_in->color,
+ shadow_spec_in->xoffset * xscale_in,
+ shadow_spec_in->yoffset * yscale_in,
+ shadow_spec_in->blur * scale,
+ shadow_spec_in->spread * scale,
+ shadow_spec_in->inset);
+ }
+ else
+ {
+ shadow_spec = st_shadow_ref (shadow_spec_in);
+ }
+
/* We want the output to be a color agnostic alpha mask,
* so we need to strip the color channels from the input
*/
width_out,
height_out,
rowstride_out);
+ cairo_surface_set_device_scale (surface_out, xscale_in, yscale_in);
cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
pixels_out, (cairo_destroy_func_t) g_free);
if (shadow_spec->inset)
{
+ /* Scale the matrix in surface absolute coordinates */
+ cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
+
/* For inset shadows, offsets and spread radius have already been
* applied to the original pattern, so all left to do is shift the
* blurred image left, so that it aligns centered under the
cairo_matrix_translate (&shadow_matrix,
(width_out - width_in) / 2.0,
(height_out - height_in) / 2.0);
+
+ /* Scale back the matrix in original coordinates */
+ cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
+
cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
return dst_pattern;
}
/* 6. Invert the matrix back */
cairo_matrix_invert (&shadow_matrix);
+ /* Scale the matrix in surface absolute coordinates */
+ cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
+
/* 5. Adjust based on specified offsets */
cairo_matrix_translate (&shadow_matrix,
shadow_spec->xoffset,
- (width_out - width_in) / 2.0,
- (height_out - height_in) / 2.0);
+ /* Scale back the matrix in scaled coordinates */
+ cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
+
/* 1. Invert the matrix so we can work with it in pattern space
*/
cairo_matrix_invert (&shadow_matrix);
{
cairo_surface_t *surface;
int width, height;
+ double xscale, yscale;
cairo_matrix_t matrix;
cairo_save (cr);
/* Something went wrong previously */
goto no_surface;
+ cairo_surface_get_device_scale (surface, &xscale, &yscale);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
cairo_pattern_get_matrix (pattern, &matrix);
cairo_matrix_invert (&matrix);
+ cairo_matrix_scale (&matrix, 1.0 / xscale, 1.0 / yscale);
cairo_transform (cr, &matrix);
cairo_rectangle (cr, 0, height, width, - height);
int x,
int y,
int width,
- int height)
+ int height,
+ float resource_scale)
{
cairo_pattern_t *shadow_pattern;
/* Prerender the pattern to a temporary surface,
* so it's properly clipped before we create a shadow from it
*/
+ width = ceilf (width * resource_scale);
+ height = ceilf (height * resource_scale);
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cairo_surface_set_device_scale (clipped_surface, resource_scale, resource_scale);
temp_cr = cairo_create (clipped_surface);
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
static void
paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
StShadow *shadow_spec,
+ float resource_scale,
cairo_t *cr,
cairo_path_t *shadow_outline)
{
/* Bounds of temporary surface */
int surface_x = floor (shrunk_extents_x1);
int surface_y = floor (shrunk_extents_y1);
- int surface_width = ceil (shrunk_extents_x2) - surface_x;
- int surface_height = ceil (shrunk_extents_y2) - surface_y;
+ int surface_width = ceil ((shrunk_extents_x2 - surface_x) * resource_scale);
+ int surface_height = ceil ((shrunk_extents_y2 - surface_y) * resource_scale);
/* Center of the original path */
double x_center = (extents_x1 + extents_x2) / 2;
cairo_matrix_t matrix;
shadow_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, surface_width, surface_height);
+ cairo_surface_set_device_scale (shadow_surface, resource_scale, resource_scale);
temp_cr = cairo_create (shadow_surface);
/* Match the coordinates in the temporary context to the parent context */
has_visible_outline? outline_path : NULL,
actor_box.x1,
actor_box.y1,
- width, height);
+ width, height,
+ resource_scale);
cairo_append_path (cr, outline_path);
}
{
paint_inset_box_shadow_to_cairo_context (node,
box_shadow_spec,
+ resource_scale,
cr,
interior_path ? interior_path
: outline_path);